package com.ctshk.rpc.localfun.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.dto.Result;
import com.ctshk.common.enums.ApprovalStatus;
import com.ctshk.common.enums.ScenicApproveType;
import com.ctshk.common.enums.SystemError;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.model.PageResponse;
import com.ctshk.common.model.TokenUser;
import com.ctshk.common.utils.EntityUtil;
import com.ctshk.rpc.localfun.dto.*;
import com.ctshk.rpc.localfun.entity.*;
import com.ctshk.rpc.localfun.enums.ProductCenterEnum;
import com.ctshk.rpc.localfun.mapper.*;
import com.ctshk.rpc.localfun.req.LocalFunProductCostReq;
import com.ctshk.rpc.localfun.req.LocalFunReservationListReq;
import com.ctshk.rpc.localfun.req.LocalFunReservationOrderReq;
import com.ctshk.rpc.localfun.service.ILocalFunCostPriceService;
import com.ctshk.rpc.localfun.service.ILocalFunProductService;
import com.ctshk.rpc.localfun.service.ILocalFunReservationService;
import com.ctshk.rpc.localfun.util.NumberUtil;
import com.ctshk.rpc.system.dto.SysDepartmentDTO;
import com.ctshk.rpc.system.service.IMainDataCurrencyService;
import com.ctshk.rpc.system.service.ISysDepartmentService;
import com.github.xiaoymin.knife4j.core.util.CollectionUtils;
import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @Description
 * @Author wansi <gaylen15527491065@yeah.net>
 * @Date 2021/3/25
 */
@DubboService
public class LocalFunReservationServiceImpl extends ServiceImpl<LocalFunProductMapper, LocalFunProduct> implements ILocalFunReservationService {

    @Autowired
    private LocalFunProductMapper localFunProductMapper;

    //汇率服务
    @DubboReference
    private IMainDataCurrencyService mainDataCurrencyService;
    @Autowired
    private LocalFunProductCostStrategySpecStockMapper costStrategySpecStockMapper;
    @Autowired
    private LocalFunProductCostStrategyVaildDateMapper costStrategyVaildDateMapper;
    @Autowired
    private LocalFunProductSaleStrategyVaildDateMapper saleStrategyVaildDateMapper;
    @Autowired
    private LocalFunProductCostStrategyMapper costStrategyMapper;
    @Autowired
    private LocalFunProductChannelOfflineMapper channelOfflineMapper;
    @DubboReference
    private ILocalFunCostPriceService iLocalFunCostPriceService;
    @Autowired
    private LocalFunProductChannelOfflineSelfCustomMapper channelOfflineSelfCustomMapper;

    @DubboReference
    private ISysDepartmentService iSysDepartmentService;
    @DubboReference
    private ILocalFunProductService iLocalFunProductService;



    @Override
    public PageResponse<LocalFunReservationListDTO> queryList(LocalFunReservationListReq req, TokenUser tokenUser) {
        IPage<LocalFunProduct> iPage = new Page<>(req.getPageNo(), req.getPageSize());
        //分页查询结果集
        IPage<LocalFunProduct> insuranceIPage = baseMapper.queryReserveProductList(iPage, req);

        if (CollectionUtils.isNotEmpty(insuranceIPage.getRecords())) {
            List<LocalFunReservationListDTO> localFunResourceDTOList = EntityUtil.copyList(insuranceIPage.getRecords(), LocalFunReservationListDTO.class);
            //产品列表查询，成本有效期时间为空，需要设置
            setCostValidateTime(localFunResourceDTOList);
            //权限校验产品过滤
            localFunResourceDTOList = productPrivilegeVisitable(localFunResourceDTOList,tokenUser);
            localFunResourceDTOList = localFunResourceDTOList.stream().filter(entity->entity.getCostPrice() != null).collect(Collectors.toList());
            return new PageResponse(localFunResourceDTOList, iPage.getCurrent() == 1, localFunResourceDTOList.size() <= (iPage.getCurrent() * iPage.getSize()), localFunResourceDTOList.size(), iPage.getCurrent(), iPage.getSize());
        }
        return new PageResponse<>(new ArrayList<>(), iPage.getCurrent() == 1, iPage.getTotal() <= (iPage.getCurrent() * iPage.getSize()), iPage.getTotal(), iPage.getCurrent(), iPage.getSize());
    }


    @Override
    public List<LocalFunReservationListDTO> recommendedList(TokenUser tokenUser) {
        //默认推荐15个
        List<LocalFunReservationListDTO> productDtoList = localFunProductMapper.recommendedList();
        //权限校验产品过滤
        productDtoList = productPrivilegeVisitable(productDtoList,tokenUser);
        return productDtoList;
    }


    /**
     * 权限校验产品过滤
     * @param productDtoList
     * @param tokenUser
     * @return
     */
    private List<LocalFunReservationListDTO> productPrivilegeVisitable(List<LocalFunReservationListDTO> productDtoList,TokenUser tokenUser){
        //产品开售过滤
        LocalDate nowDate = LocalDate.now();

        productDtoList = productDtoList.stream()
                .filter(entity->checkConditional(entity,tokenUser,nowDate))
                .collect(Collectors.toList());

        if(CollectionUtils.isEmpty(productDtoList)){
            return productDtoList;
        }

        //设置产品价格：成本价+幅加费
        addFee(tokenUser, productDtoList, nowDate);
        productDtoList = productDtoList.stream().filter(entity->entity.getCostPrice() != null).collect(Collectors.toList());
        return productDtoList;
    }


    /**
     * 产品过滤条件
     * @param entity
     * @param tokenUser
     * @param nowDate
     * @return
     */
    private boolean checkConditional(LocalFunReservationListDTO entity, TokenUser tokenUser, LocalDate nowDate) {
        AtomicInteger count = new AtomicInteger();

        //立即開售，無需校驗開售日期
        if(ProductCenterEnum.CANCELPOLICY_SHE.getChannelCode().equals(entity.getStartSaleTimeType())){
            //1.过滤出产品开售日期范围包括当天的产品
            if(entity.getStartSaleTimeBegin().compareTo(nowDate) <= 0 &&
                    entity.getStartSaleTimeEnd().compareTo(nowDate) >= 0){
                count.addAndGet(1);
            }
        }else {
            count.addAndGet(1);
        }
        //2.过滤出产品规格成本有效期范围在当天的产品
        if(entity != null && entity.getTimeBegin() != null && entity.getTimeBegin().compareTo(nowDate) <= 0 &&
                entity.getTimeEnd().compareTo(nowDate) >= 0){
            count.addAndGet(1);
        }
        //3.过滤出产品规格幅加策略有效期范围在当天的产品
        if(entity.getSaleTimeBegin() != null && entity.getSaleTimeBegin().compareTo(nowDate) <= 0 &&
                entity.getSaleTimeEnd().compareTo(nowDate) >= 0){
            count.addAndGet(1);
        }
        //4.用户已授权用户可见，其他权限暂未处理
        if(checkUserVisiable(entity,tokenUser.getId())){
            count.addAndGet(1);
        }

        //5.仅限打包的产品在预订中心不可见
        if(entity.getAllowPackage() != 3){
            count.addAndGet(1);
        }

        return count.get() == 5;
    }


    /**
     * 设置成本价有效期
     * @param productDtoList
     */
    private void setCostValidateTime(List<LocalFunReservationListDTO> productDtoList) {
        for(LocalFunReservationListDTO entity :productDtoList){
            //成本有效期 最小时间~最大时间
            LocalFunProductCostStrategyVaildDate vaildDate = costStrategyVaildDateMapper.selectValidteTime(entity.getId());
            if(vaildDate != null){
                entity.setTimeBegin(vaildDate.getTimeBegin());
                entity.setTimeEnd(vaildDate.getTimeEnd());
            }

            //加辐有效期 最小时间~最大时间
            LocalFunProductSaleStrategyVaildDate vaildSaleDate = saleStrategyVaildDateMapper.selectValidteTime(entity.getId());
            if(vaildSaleDate != null){
                entity.setStrategyId(vaildSaleDate.getStrategyId());
                entity.setSaleTimeBegin(vaildSaleDate.getTimeBegin());
                entity.setSaleTimeEnd(vaildSaleDate.getTimeEnd());
            }
        }
    }

    /**
     * 校验用户可见
     * @param entity
     * @param id
     * @return
     */
    private boolean checkUserVisiable(LocalFunReservationListDTO entity, Long id) {
        if(entity.getStrategyId() == null){
            Result<Long> result = iLocalFunProductService.getExactStrategyId(LocalDate.now(), entity.getId());
            entity.setStrategyId(result.getData());
        }
        QueryWrapper<LocalFunProductChannelOffline> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(LocalFunProductChannelOffline::getStrategyId,entity.getStrategyId());
        List<LocalFunProductChannelOffline> channelOffLines = channelOfflineMapper.selectList(queryWrapper);


        //暂时只考虑自营渠道
        if(CollectionUtils.isNotEmpty(channelOffLines)){
            //1、自营 2、代理  取自营渠道权限
            LocalFunProductChannelOffline channelOffline = channelOffLines.stream().filter(en ->
                    ProductCenterEnum.SEL_CUSTOM_CHANNEL.getChannelCode().equals(en.getChannelType())).findFirst().orElse(null);

            if(channelOffline != null){
                Integer visableType = channelOffline.getVisableType();
                // 1 禁止自营   所有用户不可见
                if(ProductCenterEnum.SEL_CUSTOM_FORBID == visableType){
                    return false;
                }
                //2 所有部门   所有部门可见
                else if(ProductCenterEnum.ALL_DEPT_SALE == visableType){
                    return true;
                }
                //2 指定人员、部门可见
                else if(ProductCenterEnum.PERSONAL_SALE == visableType){
                    QueryWrapper<LocalFunProductChannelOfflineSelfCustom> customQueryWrapper = new QueryWrapper<>();
                    //人员 checkType 1:部门 2：员工
                    customQueryWrapper.lambda().eq(LocalFunProductChannelOfflineSelfCustom::getOfflineId,channelOffline.getId());
                    List<LocalFunProductChannelOfflineSelfCustom> selfCustomList = channelOfflineSelfCustomMapper.selectList(customQueryWrapper);

                    //校验 自营渠道，当前用户匹配指定部门、人员可见
                    if(CollectionUtils.isNotEmpty(selfCustomList)){
                        SysDepartmentDTO sysDepartmentDTO = iSysDepartmentService.queryByUserId(id);
                        return selfCustomList.stream().anyMatch(en->en.getRelationId() !=null && en.getRelationId().equals(id)
                                || en.getRelationId() !=null && en.getRelationId().equals(sysDepartmentDTO !=null ? sysDepartmentDTO.getId() : -99));
                    }
                }
            }
        }
        return false;
    }

    /**
     * 设置产品价格：成本价+幅加费
     * @param tokenUser
     * @param productDtoList
     * @param nowDate
     */
    private void addFee(TokenUser tokenUser, List<LocalFunReservationListDTO> productDtoList, LocalDate nowDate) {
        productDtoList.forEach(entity->{

            // B端暂时只有：自营渠道加辐渠道
            // B端下订单时，如果是代理订单，则需要加上代理商加辐费用

            LocalFunProductCostReq costReq = new LocalFunProductCostReq();
            costReq.setProductId(entity.getId());
            costReq.setQueryDate(nowDate);
            costReq.setChannelType(1);
            costReq.setUserId(tokenUser.getId());
            //获取该产品当日的所有规格产品结果集
            List<LocalFunProductCostDTO> productCostList = iLocalFunCostPriceService.getProductCostList(costReq);

            if(CollectionUtils.isNotEmpty(productCostList)){
                productCostList = productCostList.stream().filter(en->en.getTimeBegin().compareTo(nowDate) <= 0 &&
                        en.getTimeEnd().compareTo(nowDate) >=0).collect(Collectors.toList());

                LocalFunProductCostDTO localFunProductCostDTO = productCostList.stream().min(Comparator.comparing(LocalFunProductCostDTO::getPrice)).get();
                if(localFunProductCostDTO != null){
                    entity.setCostPrice(NumberUtil.getDecimalPercent(localFunProductCostDTO.getPrice()));
                }
            }
        });
    }

    @Override
    public LocalFunReservationGetOrderDTO getOrderInfo(LocalFunReservationOrderReq localFunReservationOrderReq) {
        LocalFunProduct localFunProduct = localFunProductMapper.selectById(localFunReservationOrderReq.getId());
        if(null == localFunProduct){
            throw new BusinessException(SystemError.SYS_411);
        }
        LocalFunReservationGetOrderDTO dto = EntityUtil.copy(localFunProduct, LocalFunReservationGetOrderDTO.class);

        BigDecimal reserveCharge = localFunProduct.getReserveCharge();
        //预订服务费类型 按金额 1:数值  2:百分比
        if(localFunProduct.getReserveChargeType() == null || 1 == localFunProduct.getReserveChargeType()){
            dto.setServiceAomunt(localFunProduct.getReserveCharge() == null ? BigDecimal.ZERO : localFunProduct.getReserveCharge());
            QueryWrapper<LocalFunProductCostStrategySpecStock> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(LocalFunProductCostStrategySpecStock::getProductId,localFunReservationOrderReq.getId());
            if(localFunReservationOrderReq.getSpecId1() != null){
                queryWrapper.lambda().eq(LocalFunProductCostStrategySpecStock::getAttr1Id,localFunReservationOrderReq.getSpecId1());
            }
            if(localFunReservationOrderReq.getSpecId2() != null){
                queryWrapper.lambda().eq(LocalFunProductCostStrategySpecStock::getAttr2Id,localFunReservationOrderReq.getSpecId2());
            }
            List<LocalFunProductCostStrategySpecStock> specStocks = costStrategySpecStockMapper.selectList(queryWrapper);

            if(CollectionUtils.isEmpty(specStocks)){
                return dto;
            }
            LocalFunProductCostStrategySpecStock specStock = specStocks.stream().findFirst().orElse(null);
            if(specStock != null){
                dto.setAttr1Name(StringUtils.isNotEmpty(specStock.getAttr1Name()) ? specStock.getAttr1Name() :"");
                dto.setAttr2Name(StringUtils.isNotEmpty(specStock.getAttr2Name()) ? specStock.getAttr2Name() :"");
            }
        }else {
            QueryWrapper<LocalFunProductCostStrategySpecStock> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(LocalFunProductCostStrategySpecStock::getProductId,localFunReservationOrderReq.getId());
            if(localFunReservationOrderReq.getSpecId1() != null){
                queryWrapper.lambda().eq(LocalFunProductCostStrategySpecStock::getAttr1Id,localFunReservationOrderReq.getSpecId1());
            }
            if(localFunReservationOrderReq.getSpecId2() != null){
                queryWrapper.lambda().eq(LocalFunProductCostStrategySpecStock::getAttr2Id,localFunReservationOrderReq.getSpecId2());
            }
            List<LocalFunProductCostStrategySpecStock> specStocks = costStrategySpecStockMapper.selectList(queryWrapper);

            if(CollectionUtils.isEmpty(specStocks)){
                return dto;
            }

            LocalFunProductCostStrategySpecStock specStock = specStocks.stream().findFirst().orElse(null);
            if(specStock != null){
                LocalFunProductCostStrategy localFunProductCostStrategy = costStrategyMapper.selectOne(Wrappers.<LocalFunProductCostStrategy>lambdaQuery().eq(LocalFunProductCostStrategy::getId, specStock.getCostId()));
                BigDecimal multiply = reserveCharge.multiply(new BigDecimal(0.01)).multiply(specStock.getCostPrice().multiply(new BigDecimal(localFunProductCostStrategy.getExchangeRate())));
                dto.setServiceAomunt(NumberUtil.getDecimalPercent(multiply));
                dto.setAttr1Name(StringUtils.isNotEmpty(specStock.getAttr1Name()) ? specStock.getAttr1Name() :"");
                dto.setAttr2Name(StringUtils.isNotEmpty(specStock.getAttr2Name()) ? specStock.getAttr2Name() :"");
            }
        }
        //旅客所需证件
        if(StringUtils.isNotEmpty(localFunProduct.getCertificateType())){
            String[] split = localFunProduct.getCertificateType().split(",");
            dto.setCertificateTypeIds(Arrays.asList(split));
        }

        //是否可以代理下单
        List<AgentDto> agentList = localFunProductMapper.getAgent(localFunProduct.getId(), localFunReservationOrderReq.getSpecId1(), localFunReservationOrderReq.getSpecId2(), LocalDate.now());
        //未设置代理商，则不可以代理下单
        dto.setCanUseAgent(false);
        if(CollectionUtils.isNotEmpty(agentList)){
            AgentDto agentDto = agentList.stream().findFirst().orElse(null);
            if(agentDto != null){
                dto.setCanUseAgent(agentDto.getVisableType() != 1);
            }
        }
        return dto;
    }

    @Override
    public LocalFunProductDetail getLocalFunProductDetail(Long id, TokenUser tokenUser) {
        LocalFunProduct localFunProduct = localFunProductMapper.selectById(id);
        LocalFunProductDetail funProductDetail = EntityUtil.copy(localFunProduct, LocalFunProductDetail.class);

        QueryWrapper<LocalFunProductCostStrategySpecStock> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(LocalFunProductCostStrategySpecStock::getProductId,id);
        List<LocalFunProductCostStrategySpecStock> costStrategySpecStocks = costStrategySpecStockMapper.selectList(queryWrapper);
        if(CollectionUtils.isEmpty(costStrategySpecStocks)){
            return funProductDetail;
        }

        LocalDate nowDate = LocalDate.now();

        LocalFunProductCostReq costReq = new LocalFunProductCostReq();
        costReq.setProductId(localFunProduct.getId());
        costReq.setQueryDate(nowDate);
        costReq.setUserId(tokenUser.getId());
        costReq.setChannelType(1);
        List<LocalFunProductCostDTO> productCostList = iLocalFunCostPriceService.getProductCostList(costReq);

        if(CollectionUtils.isNotEmpty(productCostList)){
            productCostList = productCostList.stream().filter(en->en.getTimeBegin().compareTo(nowDate) <= 0 &&
                    en.getTimeEnd().compareTo(nowDate) >=0).collect(Collectors.toList());

            funProductDetail.setSpecList(productCostList.stream().map(entity->{
                SpecAttributeDTO specAttributeDTO = new SpecAttributeDTO();
                specAttributeDTO.setSpecId1(entity.getAttr1Id());
                specAttributeDTO.setSpecName1(entity.getAttr1Name());
                specAttributeDTO.setSpecId2(entity.getAttr2Id());
                specAttributeDTO.setSpecName2(entity.getAttr2Name());
                specAttributeDTO.setMoney(NumberUtil.getDecimalPercent(entity.getPrice() != null ? entity.getPrice().setScale(2, BigDecimal.ROUND_HALF_UP): null));
                specAttributeDTO.setMoreTicket(entity.getTotalStock());
                return specAttributeDTO;
            }).collect(Collectors.toList()));
        }
        return funProductDetail;
    }

    @Override
    public List<LocalFunReservationListDTO> recommendedList2(TokenUser tokenUser) {
        //默认查询出发日期明天
        List<String> relationList = getUserIdsByUserId(tokenUser.getId());
        List<LocalFunReservationListDTO> recommendedList = localFunProductMapper.getRecommendedList(relationList, LocalDate.now());
        if(CollectionUtils.isNotEmpty(recommendedList)){
            recommendedList = recommendedList.stream().filter(entity->entity.getStartSaleTimeType() == 1 ? true : entity.getStartSaleTimeBegin().compareTo(LocalDate.now()) <= 0 &&
                    entity.getStartSaleTimeEnd().compareTo(LocalDate.now()) >= 0).filter(entity-> candidateRelation(relationList, entity)).collect(Collectors.toList());
            for (LocalFunReservationListDTO dto : recommendedList) {
                if (dto.getAdjustType() == ProductCenterEnum.AMOUNT.getChannelCode()) {
                    dto.setCostPrice(dto.getCostPrice().add(dto.getAmount()));
                } else if (dto.getAdjustType() == ProductCenterEnum.PERCENT.getChannelCode()) {
                    double percent = dto.getPercent() != null ? dto.getPercent().doubleValue() * 0.01 : 0;
                    dto.setCostPrice(dto.getCostPrice().add(dto.getCostPrice().add(BigDecimal.valueOf(percent))));
                }
            }
        }
        return recommendedList;
    }

    /**
     * 是否有产品权限
     * 禁售没有权限 false
     * 全部部门都有权限 true
     * 选择按人或部门匹配 匹配成功ture 否则 false
     * @param relationList
     * @param entity
     * @return
     */
    private boolean candidateRelation(List<String> relationList, LocalFunReservationListDTO entity) {
        if(entity.getVisableType() ==1){
            return false;
        }else if(entity.getVisableType()==2){
            return true;
        }else {
            if(relationList.contains(entity.getRelationId())){
                return true;
            }else {
                return false;
            }
        }
    }

    private List<String> getUserIdsByUserId(Long id) {
        List<Long> longs = iSysDepartmentService.queryIdsByUserId(id);
        longs.add(id);
        String stringBuffer = "";
        for (Long aLong : longs) {
            stringBuffer += aLong.toString() + ",";
        }
        if (!"".equals(stringBuffer)) {
            stringBuffer = stringBuffer.substring(0, stringBuffer.length() - 1);
        }
        return Lists.newArrayList(stringBuffer.split(","));
    }

    private QueryWrapper<LocalFunProduct> queryParamCondition(LocalFunReservationListReq req) {
        QueryWrapper<LocalFunProduct> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(req.getCityName())) {
            queryWrapper.lambda().like(LocalFunProduct::getCityName, req.getCityName());
        }
        if (req.getCityId() != null && req.getCityId() != 0L) {
            queryWrapper.lambda().eq(LocalFunProduct::getCityId, req.getCityId());
        }
        if (req.getFunType() != null && req.getFunType() != 0L) {
            queryWrapper.lambda().eq(LocalFunProduct::getFunType, req.getFunType());
        }
        if (StringUtils.isNotBlank(req.getName())) {
            queryWrapper.lambda().like(LocalFunProduct::getName, req.getName());
        }
        if (StringUtils.isNotBlank(req.getFunName())) {
            queryWrapper.lambda().like(LocalFunProduct::getFunName, req.getFunName());
        }
        queryWrapper.lambda().eq(LocalFunProduct::getStatus,1);
        return queryWrapper;
    }
}
